Skip to content

fix(operator-trend): floor rererestore persistence magnitude (T3-2 phase 5)#80

Merged
saagpatel merged 1 commit into
mainfrom
fix/operator-trend-rererestore-magnitude-floor
Jun 20, 2026
Merged

fix(operator-trend): floor rererestore persistence magnitude (T3-2 phase 5)#80
saagpatel merged 1 commit into
mainfrom
fix/operator-trend-rererestore-magnitude-floor

Conversation

@saagpatel

Copy link
Copy Markdown
Owner

The bug

closure_forecast_reset_reentry_rebuild_reentry_restore_rererestore_persistence_for_target decremented per-event magnitude without the max(0.0, ..) floor that its rebuild sibling applies:

# rebuild (correct)              # rererestore (buggy)
magnitude = max(0.0, mag - 0.10) magnitude -= 0.10

magnitude is per-event evidence strength — non-negative by concept, with sign (±1 by side) carrying direction. Without the floor, an over-penalized confirmation event (mixed-age freshness + a reset signal) drives magnitude negative, and sign * magnitude then makes that confirmation event count against its own side — a confirmation-side target can get a spurious clearance-leaning persistence_score.

The fix

Floor the 4 decrements (L5776/5778/5780/5788) to match rebuild. On the same structural input the two tiers now agree, and the rerererestore wrapper that delegates to this builder stops producing a spurious negative:

scenario before after
rererestore persistence_score 0.24 0.31 (== rebuild)
rerererestore (wrapper) persistence_score -0.08 0.09

Caught by the phase-4 net

The composer characterization golden (#79) caught this exactly: the regenerated golden diff is 3 score lines, and the anchor test flips from pinning the divergence to pinning the convergence (test_magnitude_floor_unifies_rebuild_and_rererestore_tiers). No existing test pinned the buggy value — the negative-magnitude path was uncharacterized, which is precisely why the bug survived until the net drove it.

Verification

  • Full suite green (2539 passed, 2 skipped) — zero mirror-test breakage
  • mypy on the edited source clean; ruff check src/ tests/ clean
  • Golden diff is the minimal 3-line behavior change

…ase 5)

The rererestore persistence builder decremented per-event `magnitude` without the
`max(0.0, ..)` floor its rebuild sibling applies. `magnitude` is per-event evidence
strength (non-negative by concept; `sign` carries the direction), so an
over-penalized confirmation event went negative and -- after `sign` -- counted
against its own side, producing a spurious clearance-leaning persistence_score.

Floor the 4 decrements to match rebuild. On the same structural input the two tiers
now agree (persistence_score 0.31 == 0.31, was 0.31 vs 0.24), and the rerererestore
wrapper that delegates to it no longer yields a spurious negative (-0.08 -> 0.09).

The phase-4 composer golden caught this exactly: the regenerated golden diff is 3
score lines, and the anchor test flips from pinning the divergence to pinning the
convergence (test_magnitude_floor_unifies_rebuild_and_rererestore_tiers). No
existing test pinned the buggy value -- the negative-magnitude path was
uncharacterized, which is why the bug survived.
@saagpatel saagpatel merged commit f3d4aaf into main Jun 20, 2026
3 checks passed
saagpatel added a commit that referenced this pull request Jun 20, 2026
…trized base (T3-2 phase 6) (#82)

The rebuild and rererestore persistence builders were ~190-line hand-clones of one
algorithm -- proven identical by the phase-4 composer golden, the floor fix (#80),
and a differential test over the net's corpus. Extract a single
_persistence_for_target_base plus a _PersistenceTierSpec carrying the per-tier
literals (status keys, status tokens, reason prose, output keys); both public
builders become thin wrappers that pass their spec.

Public signatures are unchanged, so the apply-chain wiring, the rerererestore
delegation wrapper (which injects the rererestore builder), and all other callers
are untouched.

Net -121 lines (265 insertions, 386 deletions). The composer golden is
byte-identical -- a correct collapse changes no output -- and the full suite (2539
passed) is green. Correctness is demonstrated, not assumed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant